void print_attriblist(vector<attrib_field*> v)
{
	for(int ii=0;ii<v.size();ii++)
		v[ii]->print();
}

void print_attriblist_values(vector<attrib_field*> attlist)
{
	PRINT("\n");

	for(int ii=0;ii<attlist.size();ii++)
	{
		if(attlist[ii]->agg_type == ISNULL_TYPE)
			attlist[ii]->printvalue(1);
		else
		{
			attlist[ii]->print();
			FATAL("Print call with invalid AGG-TYPE\n");
		}
	}
	PRINT("\n");
}

void print_attriblist_values(vector<attrib_field*> attlist, int count)
{
	PRINT("\n");
	for(int ii=0;ii<attlist.size();ii++)
	{
		attlist[ii]->printvalue(count);
	}
	PRINT("\n");
}

int get_field_type(char *str, attrib_field *field)
{
	size_t found;
	
	DBGPRINTS(str);
	
	/*** Check if it is an attribute ***/
	if(isalpha(str[0]))
	{
		if(NULL != strchr(str, '.'))
		{
			char *delim=".";

			strcpy(field->tablename, strtok(str, delim));
			strcpy(field->attribname, strtok(NULL,delim));
			return ISTATTRIB_TYPE;
		}
		else if(strcmp(str,"SUM")==0)
		{
			field->agg_type = SUM;
			return ISAGGREGATE_TYPE;
		}
		else if(strcmp(str,"AVG")==0)
		{
			field->agg_type = AVG;
			return ISAGGREGATE_TYPE;
		}
		else if(strcmp(str,"MIN")==0)
		{
			field->agg_type = MIN;
			return ISAGGREGATE_TYPE;
		}
		else if(strcmp(str,"MAX")==0)
		{
			field->agg_type = MAX;
			return ISAGGREGATE_TYPE;
		}
		else if(strcmp(str,"COUNT")==0)
		{
			field->agg_type = COUNT;
			return ISAGGREGATE_TYPE;
		}
		else
		{
			strcpy(field->attribname,str);
			return ISATTRIB_TYPE;
		}
	}
	else
	{
		if(strcmp(str,">")==0)
		{
			field->value = OP_GR;
			return ISOPERATOR_TYPE;
		}
		else if(strcmp(str,"<") ==0)
		{
			field->value = OP_LS;
			return ISOPERATOR_TYPE;
		}
		else if(strcmp(str,"=")==0)
		{
			field->value = OP_EQ;
			return ISOPERATOR_TYPE;
		}
		else if(strcmp(str,">=")==0)
		{
			field->value = OP_GEQ;
			return ISOPERATOR_TYPE;
		}
		else if(strcmp(str,"<=")==0)
		{
			field->value = OP_LEQ;
			return ISOPERATOR_TYPE;
		}
		else if(strcmp(str, "*")==0)
		{
			strcpy(field->attribname,str);
			return ISATTRIB_TYPE;
		}
		else
		{
			field->value = atoi(str);
			return ISNUMBER_TYPE;
		}
	}
}


int extract_tokens(const char *query)
{
        char *space = " ";
	char *obrace = "(";
	char *cbrace = ")";
	char *comma = ",";
	char *terminate = "\0";
	char *scolon = ";";
	char equal = '=';
	char grtr = '>';
	char lssr = '<';
	int index=0, prev=0;
	int i=0;

#define CHAR_FOUND 1
#define PUNC_FOUND 2

	token_num=0;
	memset((void *) tokens,0, 100);

	for(i=0;i<MAX_QUERY_SIZE;i++)
	{
		if(strncmp(&query[i],terminate,1))	
		{
			if( (query[i]=='=')
				|| (query[i] == '<')
				|| (query[i] == '>'))
			{
				tokens[token_num][index++]='\0';
				token_num++;index=0;

				tokens[token_num][index++] = query[i];
				tokens[token_num][index++]='\0';
				token_num++;index=0;
				prev =  CHAR_FOUND;

			}else if(strncmp(&query[i],space,1)
				&& strncmp(&query[i],obrace,1) 
				&& strncmp(&query[i],comma,1) 
				&& strncmp(&query[i],cbrace,1)
				&& strncmp(&query[i],scolon,1) )
			{
				// Store the letter in the query and move index to store the next letter
				 tokens[token_num][index++] = query[i];
				 // Hack to check when punctuation marks hit continuously
				 prev = CHAR_FOUND;
		        }
			else if(';' == query[i])
			{
				tokens[token_num][index++]='\0';
				if(prev != PUNC_FOUND) {
					token_num++;
				}
				break;				
			}
			else
			{
				// Found a punctuation set the string in earlier token and goto next letter in the query
				 // Hack to check when punctuation marks hit continuously
				if(prev == CHAR_FOUND){
					tokens[token_num][index]='\0';
					token_num++;index=0;
				}
				prev = PUNC_FOUND;
			}
		}
	}

	DBGPRINTN(token_num);
	DBGPRINT("\n");
	for (i=0;i<token_num;i++)
	{
		DBGPRINT("%*d ",strlen(tokens[i]),i%10); 
	}
	DBGPRINT("\n");
	for (i=0;i<token_num;i++)
	{
		DBGPRINT("%s ",tokens[i]);
	}
	DBGPRINT("\n");

	return(0);

}

#define DIFFTIME(x,y)	((y.tv_sec - x.tv_sec)*100000 + (y.tv_usec - x.tv_usec))
#define START	gettimeofday(&t_start, &tz1);
#define END	gettimeofday(&t_finish, &tz1);(timer? PRINT("\n\nCommand Time: %lu usecs \n" , DIFFTIME(t_start, t_finish)) :PRINT("\n"));PROMPT;

int create_table()
{
	int i=0, status=0;
	tableinfo tinfo;
	

	extract_tokens(lexer->YYText());
	// TABLE NAME is 3 token, skipping create TABLE T1 a1, a2
	strcpy(tinfo.table_name, tokens[2]);

	DBGPRINTN(token_num);
	for(i=3;i<token_num;i++)
	{
		strcpy(tinfo.attrib_names[i-3],tokens[i]);

		/* Initializing min and max fields to zero */
		tinfo.min[i-3] = 0;
		tinfo.max[i-3] = 0;
	}
	tinfo.num_of_attribs =  (token_num - 3);
	DBGPRINTN(tinfo.num_of_attribs);

	tinfo.num_of_records = 0;
	tinfo.num_indexes = 0;

	DBGPRINTN(tinfo.num_of_records);
	DBGPRINTN(tinfo.num_indexes);

	status = db1->add_table(&tinfo);
	
	return(status);
}

int insert_values()
{
	int i=0;
	char tablename[TABLE_NAME_LENGTH];
	int attrib[MAX_NUM_ATTRIBS];

	
	extract_tokens(lexer->YYText());

	strcpy(tablename, tokens[2]);

	// Skip 4 tokens for (INSERT, INTO, TBLNAME, VALUES)
	for(i=4; i<token_num; i++)
		attrib[i-4] = atoi(tokens[i]);

	//for(i=0; i<token_num-4; i++) DBGPRINTF("%d\n",attrib[i]);

	DBGPRINTF("num values is %d\n", token_num-4);
	if(db1->insert_record(tablename, token_num-4, attrib))
	{
		FATAL("Either Table Name or Number of Values is wrong\n");
		return DATA_NOT_FOUND;
	}
	
	// get table name from token 1
	// check that no of values = table's num-attribues
	// use atoi() for converting ascii to integers
	// get values from 2 to end
	return(0);
}


/*** Select command: select *|[a1,a2,a3] from <Tablename>  where T1a=T2b AND <... goes to query structure> ***/
/***			0   1, 2, 3    	*/  
int select_join_call()
{

	int i=0, num_attribs=0;

	vector<attrib_field*> attrib_list;
	char tname1[TABLE_NAME_LENGTH]="\0";
	char tname2[TABLE_NAME_LENGTH]="\0";
	int is_join = 0;

	int is_agg = 0;	// for calling Aggregate function separately ???
	int field_type;
	attrib_field *temp_field=NULL;

	extract_tokens(lexer->YYText());

	
	condition *head = NULL;
	
	//i=0; skip the word select
	i++;

	num_attribs=0;
	while(strcmp(tokens[i], "FROM") !=0 ) {
		temp_field = new attrib_field();

		DBGPRINTS(tokens[i]);
		field_type = get_field_type(tokens[i],temp_field);

		if(field_type != ISAGGREGATE_TYPE && is_agg!=1) {
			attrib_list.push_back(temp_field);
			temp_field = NULL;
			num_attribs++;
		}
		else if(field_type != ISAGGREGATE_TYPE && is_agg==1) {
			FATAL("INVALID AGGREGATE SYNTAX");
			print_attriblist(attrib_list);
		}
		else if(field_type == ISAGGREGATE_TYPE) {
			field_type = get_field_type(tokens[++i],temp_field);
			attrib_list.push_back(temp_field);
			is_agg = 1;
		
		}
		i++;
	}

	DBGPRINTN(num_attribs);
	

	i++; // Skip the token "FROM"
	strcpy(tname1, tokens[i++]);
	DBGPRINTS(tname1);

	if(i<token_num) {

		/*** Next token is tablename in Join calls ***/
		if(strcmp(tokens[i],"WHERE") != 0) {
			is_join=1;
			strcpy(tname2, tokens[i++]); 
			DBGPRINTS(tname2);
		}
	
		if(i < token_num && strcmp(tokens[i],"WHERE") == 0) {
	
			i++;	//Skip the token "WHERE"
			condition *c1 = (condition *) malloc(sizeof(condition));
			head =  c1;
			condition *j_qry=NULL;
			while(i < token_num)
			{
				/*** First Operand in the condition ***/
				temp_field = new attrib_field();
				field_type = get_field_type(tokens[i++],temp_field);
				c1->isfield1 = field_type;
				c1->f1 = temp_field;
				
				/*** Operator in the condition ***/
				temp_field = new attrib_field();
				field_type = get_field_type(tokens[i++],temp_field);
				c1->op = temp_field->value;
				free(temp_field);
	
				
				/*** Second Operand in the condition ***/
				temp_field = new attrib_field();
				field_type = get_field_type(tokens[i++],temp_field);
				c1->isfield2 = field_type;
				c1->f2 = temp_field;
				
				if(is_join == 1 && j_qry==NULL)
				{
					if((c1->isfield1 == ISTATTRIB_TYPE) && (c1->isfield2 == ISTATTRIB_TYPE) && (c1->op == OP_EQ))
					{
						j_qry = c1;
						c1 = NULL;
						head = NULL;
					}
					/*** Check for more conditions in the query ***/
					if(i<token_num)
					{
						c1 = (condition *) malloc(sizeof(condition));
						head = c1;
						i++;//skip 'AND'
							
					}

				}
				else
				{
					if(i<token_num)
					{
						condition *temp = (condition *) malloc(sizeof(condition));
						
						temp->isfield1 = ISCONDITION_TYPE;
						temp->f1 = head;
						temp->op = OP_AND;
						temp->isfield2 = ISCONDITION_TYPE;
						temp->f2 = malloc(sizeof(condition));
		
						/***  Loop continues by filling other conditions ***/
						c1 = (condition *) temp->f2;
						head = temp;
						i++;//skip 'AND'
							
					}
				}
			}

			if(is_join)
				status = db1->join_tables(tname1, tname2, attrib_list, j_qry,  head);
			else
				status = db1->select_call(tname1, attrib_list, head);

		} else if (is_join) {
			status = db1->join_tables(tname1, tname2, attrib_list, NULL, NULL);
		} else {
			CODEME;
		}
	}
	else
	{
		/*** No params after tname1 ==> select call without where qry ***/
		status = db1->select_call(tname1, attrib_list, NULL);
	}
		return status;
}

/*** Index command: CREATE INDEX <IndexName> ON <TableName>(<AttribName>) ***/
/***			0    1        2       3      4          5         ***/  
int create_index(int flag)
{
	char iname[FILE_NAME_LENGTH];
	char tname[TABLE_NAME_LENGTH];
	char attrib[ATTRIB_NAME_LENGTH];

	extract_tokens(lexer->YYText());

	strcpy(iname, tokens[2]);
	strcpy(tname, tokens[4]);
	strcpy(attrib, tokens[5]);

	DBGPRINTS(tname);
	DBGPRINTS(iname);
	DBGPRINTS(attrib);

	if(db1->create_index(tname, iname, attrib, flag))
	{
		FATAL("Index %s cannot be created on %s\n", iname, attrib);
		return(DATA_NOT_FOUND);
	}
	
	return(0);
}

/*** Index command: PRINT INDEX <IndexName> ***/
/***			0    1        2     ***/  
void print_index()
{
	char iname[FILE_NAME_LENGTH];

	extract_tokens(lexer->YYText());

	strcpy(iname, tokens[2]);

	DBGPRINTS(iname);

	if(db1->print_index(iname))
	{
		FATAL("Index %s not found\n", iname);
	}
}

void print_hit_rate()
{
	db1->print_hit_rate();
}

void print_buffers()
{
	db1->print_buffers();
}

void print_buffer()
{
	//db1->print_buffers();
}


void print_catalog()
{
	db1->print();
}

void print_table()
{
	char tablename[TABLE_NAME_LENGTH];

	extract_tokens(lexer->YYText());

	//PRINT TABLE T1;
	strcpy(tablename, tokens[2]);
	db1->print(tablename);
}

void commit()
{

	db1->commit();

}

int quit()
{
	db1->commit();
	delete db1;
	return (0);
}
